/***************************************************************************************
 * Copyright (c) 2014-2024 Zihao Yu, Nanjing University
 *
 * NEMU is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan
 *PSL v2. You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 *KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 *NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *
 * See the Mulan PSL v2 for more details.
 ***************************************************************************************/

#include "common.h"
#include <assert.h>
#include <isa.h>
#include <macro.h>

/* We use the POSIX regex functions to process regular expressions.
 * Type 'man regex' for more information about POSIX regex functions.
 */
#include <regex.h>
// #include "include/common.h"

enum {
  TK_NOTYPE = 256,
  TK_EQ,

  /* TODO: Add more token types */
  TOKEN_PLUS = 1,
  TOKEN_SUB = 2,
  TOKEN_MUL = 3,
  TOKEN_DIV = 4,

  TOKEN_LPAREN = 5,
  TOKEN_RPAREN = 6,

  // TOKEN_LEQ = 7,
  TOKEN_EQ = 8,
  TOKEN_NOTEQ = 9,

  TOKEN_OR = 10,
  TOKEN_AND = 11,
  TOKEN_NOT = 12,

  TOKEN_REGISTER = 13,
  TOKEN_HEX = 14,
  TOKEN_NUM = 15,
};

static struct rule {
  const char *regex;
  int token_type;

} rules[] = {

    /* TODO: Add more rules.
     * Pay attention to the precedence level of different rules.
     */

    {" +", TK_NOTYPE},   // spaces
    {"\\+", TOKEN_PLUS}, // plus
    {"\\-", TOKEN_SUB},  // sub
    {"\\*", TOKEN_MUL},  // mul
    {"\\/", TOKEN_DIV},  // div

    {"\\(", TOKEN_LPAREN},
    {"\\)", TOKEN_RPAREN},

    //{"\\<\\=", TOKEN_LEQ},
    {"\\=\\=", TOKEN_EQ},
    {"\\!\\=", TOKEN_NOTEQ},

    {"\\|\\|", TOKEN_OR},
    {"\\&\\&", TOKEN_AND},
    {"\\!", TOKEN_NOT},

    //{"\\$(0|pc|ra|sp|gp|tp|t[0-6]|s[0-9]|s1[0-1]|a[0-7])", TOKEN_REGISTER},
    //{"(?:\\$(?:0|pc)|ra|sp|gp|tp|t[0-6]|s(?:[0-9]|1[0-1])|a[0-7])",
    //TOKEN_REGISTER},
    {"(\\$(0|pc)|ra|sp|gp|tp|t[0-6]|s([0-9]|1[0-1])|a[0-7])", TOKEN_REGISTER},

    {"0[xX][0-9a-fA-F]+", TOKEN_HEX},
    {"[0-9]+", TOKEN_NUM},

    //
    //{"==", TK_EQ},        // equal
};

#define NR_REGEX ARRLEN(rules)

static regex_t re[NR_REGEX] = {};

/* Rules are used for many times.
 * Therefore we compile them only once before any usage.
 */
void init_regex() {
  int i;
  char error_msg[128];
  int ret;

  for (i = 0; i < NR_REGEX; i++) {
    ret = regcomp(&re[i], rules[i].regex, REG_EXTENDED);
    if (ret != 0) {
      regerror(ret, &re[i], error_msg, 128);
      panic("regex compilation failed: %s\n%s", error_msg, rules[i].regex);
    }
  }
}

typedef struct token {
  int type;
  char str[32];
} Token;

static Token tokens[128] __attribute__((used)) = {};
static int nr_token __attribute__((used)) = 0;

static bool make_token(char *e) {
  //printf("%s\n", e);
  int position = 0;
  int i;
  regmatch_t pmatch;

  nr_token = 0;
  memset(tokens, 0, sizeof(tokens));

  while (e[position] != '\0') {
    /* Try all rules one by one. */
    //assert(0);
    for (i = 0; i < NR_REGEX; i++) {
      if (regexec(&re[i], e + position, 1, &pmatch, 0) == 0 &&
          pmatch.rm_so == 0) {
        char *substr_start = e + position;
        int substr_len = pmatch.rm_eo;

        Log("match rules[%d] = \"%s\" at position %d with len %d: %.*s", i,
            rules[i].regex, position, substr_len, substr_len, substr_start);

        position += substr_len;

        /* TODO: Now a new token is recognized with rules[i]. Add codes
         * to record the token in the array `tokens'. For certain types
         * of tokens, some extra actions should be performed.
         */
        Token tmp_token;
        switch (rules[i].token_type) {
          // default: TODO();
        case TK_NOTYPE:
          break;
        case TOKEN_PLUS:
        case TOKEN_SUB:
        case TOKEN_MUL:
        case TOKEN_DIV:
        case TOKEN_RPAREN:
        case TOKEN_LPAREN:
        case TOKEN_NOT:
          tmp_token.type = rules[i].token_type;
          tokens[nr_token++] = tmp_token;
          break;
          // case TOKEN_LEQ :
        case TOKEN_EQ:
        case TOKEN_NOTEQ:
        case TOKEN_OR:
        case TOKEN_AND:
          tmp_token.type = rules[i].token_type;
          tokens[nr_token] = tmp_token;
          nr_token++;
          break;
        case TOKEN_REGISTER:
        case TOKEN_HEX:
        case TOKEN_NUM:
          tokens[nr_token].type = rules[i].token_type;
          strncpy(tokens[nr_token].str, &e[position - substr_len], substr_len);
          tokens[nr_token].str[substr_len] = '\0'; // 确保目标字符串以 '\0' 结束
          nr_token++;
          break;
        default:
          printf("i = %d and No rules is com. \n", i);
          break;
        }

        break;
      }
    }

    if (i == NR_REGEX) {
      //printf("%s\n",e);
      printf("no match at position %d\n%s\n%*.s^\n", position, e, position, "");
      return false;
    }
  }
  // printf("完成");
  return true;
}

bool check_parenttheses(int p, int q) {
  // 首先确保最外层是括号
  if (tokens[p].type != TOKEN_LPAREN || tokens[q].type != TOKEN_RPAREN) {
    return false;
  }

  int balance = 0;

  for (int i = p; i <= q; i++) {
    if (tokens[i].type == TOKEN_LPAREN) {
      balance++; // 左括号，增加计数
    } else if (tokens[i].type == TOKEN_RPAREN) {
      balance--; // 右括号，减少计数
    }

    // 如果在遍历过程中出现了多余的右括号，直接返回false
    if (balance < 0) {
      return false;
    }

    // 当 balance 回到 0
    // 时，如果不是在最外层括号的右边界，说明内层有不匹配的括号
    if (balance == 0 && i != q) {
      return false;
    }
  }

  // 检查最后 balance 是否为0，只有为0才能说明括号是匹配的
  return balance == 0;
}

word_t eval(int p, int q) {
  if (p > q) {
    assert(0);
    return -1;
  } else if (p == q) {
    return atoi(tokens[p].str);

  } else if (check_parenttheses(p, q) == true) {
    if (p + 1 <= q - 1) {
      return eval(p + 1, q - 1);
    }
    return 0;

  } else {
    int op = -1;
    int precedence = 0;

    for (int i = p; i < q; i++) {
      // 跳过括号
      if (tokens[i].type == TOKEN_LPAREN) {
        int balance = 1;
        while (balance > 0 && i < q) {
          i++;
          if (tokens[i].type == TOKEN_LPAREN) {
            balance++;
          } else if (tokens[i].type == TOKEN_RPAREN) {
            balance--;
          }
        }
        continue; // 跳过括号内的内容
      }
      int current_precedence;
      if (tokens[i].type == TOKEN_AND)
        current_precedence = 11;
      else if (tokens[i].type == TOKEN_OR)
        current_precedence = 12;
      else if (tokens[i].type == TOKEN_NOTEQ || tokens[i].type == TOKEN_EQ)
        current_precedence = 7;
      else if (tokens[i].type == TOKEN_PLUS || tokens[i].type == TOKEN_SUB)
        current_precedence = 4;
      else if (tokens[i].type == TOKEN_MUL || tokens[i].type == TOKEN_DIV)
        current_precedence = 3;
      else
        continue; // 如果不是运算符，跳过

      // 如果当前运算符的优先级高于之前找到的运算符，则更新 op
      if (op == -1 || current_precedence >= precedence) {
        precedence = current_precedence;
        op = i;
      }
    }
    int op_type = tokens[op].type;

    word_t val1 = eval(p, op - 1);
    // printf("val1:%lu\n",val1);

    word_t val2 = eval(op + 1, q);
    // printf("val2:%lu\n",val2);
    //"4 +3*(2- 1)"  1--9

    switch (op_type) {
      // default: TODO();
    case TK_NOTYPE:
      break;
    case TOKEN_PLUS:
      return val1 + val2;
    case TOKEN_SUB:

      return val1 - val2;

    case TOKEN_MUL:
      return val1 * val2;
    case TOKEN_DIV:
      if (val2 == 0) {
        return 0;
      }
      return (sword_t)val1 / (sword_t)val2;
      // case TOKEN_NOT :

      //    break;
      // case TOKEN_LEQ :

    case TOKEN_EQ:
      return val1 == val2;
    case TOKEN_NOTEQ:
      return val1 != val2;
    case TOKEN_OR:
      return val1 || val2;
    case TOKEN_AND:
      return val1 && val2;
      // case TOKEN_REGISTER :
      // case TOKEN_HEX :
      // case TOKEN_NUM :

    default:
      printf("No Op type");
      assert(0);
    }
    return 0;
  }
}

int char2int(char s[]) {
  int s_size = strlen(s);
  int res = 0;
  for (int i = 0; i < s_size; i++) {
    res += s[i] - '0';
    res *= 10;
  }
  res /= 10;
  return res;
}
void int2char(int x, char str[]) {
  int tmp_index = 0;
  int is_negative = 0;

  // 处理负数
  if (x < 0) {
    is_negative = 1; // 标记为负数
    x = -x;          // 转换为正数
  }

  // 特殊情况：处理 x 为 0
  if (x == 0) {
    str[tmp_index++] = '0';
  } else {
    // 将数字转换为字符
    while (x > 0) {
      str[tmp_index++] = (x % 10) + '0'; // 取最后一位数字并转换为字符
      x /= 10; // 除以 10 以去掉已处理的数字
    }
  }

  // 如果是负数，添加负号
  if (is_negative) {
    str[tmp_index++] = '-';
  }

  // 反转字符串以得到正确的顺序
  str[tmp_index] = '\0'; // 添加字符串结束符
  for (int i = 0; i < tmp_index / 2; i++) {
    char temp = str[i];
    str[i] = str[tmp_index - 1 - i];
    str[tmp_index - 1 - i] = temp;
  }
}
#include <stdint.h> // 包含 uintptr_t 类型

void pretreatment() {
  // 这里先统计总共有多少个，
  int tokens_len = 0;
  for (int i = 0; i < 128; i++) {
    if (tokens[i].type == 0) {
      break;
    }
    tokens_len++;
  }

  // 处理寄存器类型
  for (int i = 0; i < tokens_len; i++) {
    if (tokens[i].type == TOKEN_REGISTER) {
      bool flag = true;
      word_t tmp = isa_reg_str2val(tokens[i].str, &flag);
      if (flag) {
        int2char(tmp, tokens[i].str);
        tokens[i].type = TOKEN_NUM;
      } else {
        printf("Transform error.\n");
        assert(0);
      }
    }
  }

  // 处理16进制数
  for (int i = 0; i < tokens_len; i++) {
    if (tokens[i].type == TOKEN_HEX) {
      int value = strtol(tokens[i].str, NULL, 16);
      int2char(value, tokens[i].str);
      tokens[i].type = TOKEN_NUM;
    }
  }

  // 去除无效的空白字符
  int write = 0;
  for (int read = 0; read < tokens_len; read++) {
    if (tokens[read].type != TK_NOTYPE) {
      tokens[write] = tokens[read];
      write++;
    }
  }
  tokens_len = write;

  // 处理单目运算符：+ - *
  for (int i = 0; i < tokens_len; i++) {
    if ((i > 0 && tokens[i - 1].type != TOKEN_NUM &&
         tokens[i - 1].type != TOKEN_RPAREN &&
         tokens[i + 1].type == TOKEN_NUM) ||
        (i == 0 && TOKEN_NUM == tokens[i + 1].type)) {

      switch (tokens[i].type) {
      case TOKEN_PLUS:
      case TOKEN_SUB: {
        int tmp2;
        tmp2 = tokens[i].type;
        tokens[i].type = TK_NOTYPE;
        for (int j = 31; j > 0; j--) {
          tokens[i + 1].str[j] = tokens[i + 1].str[j - 1];
        }
        if (tmp2 == TOKEN_PLUS) {
          tokens[i + 1].str[0] = '+';
        } else if (tmp2 == TOKEN_SUB) {
          tokens[i + 1].str[0] = '-';
        }

        break;
      }

      case TOKEN_MUL: {
        // 处理解引用符号 *

        tokens[i].type = TK_NOTYPE;

        // 获取下一个token的整数值（假设是地址）
        uintptr_t address =
            (uintptr_t)char2int(tokens[i + 1].str); // 使用 uintptr_t 类型

        if (address == 0) {
          printf("Error: Invalid memory address!\n");
          assert(0); // 地址无效，报错退出
        }

        // 解引用地址获取值
        int value = *((int *)address); // 地址转换为指针类型后进行解引用
        int2char(value, tokens[i + 1].str); // 将解引用的值转回字符串
        break;
      }
      }
    }
  }

  // 再次清理无效空格
  write = 0;
  for (int read = 0; read < tokens_len; read++) {
    if (tokens[read].type != TK_NOTYPE) {
      tokens[write] = tokens[read];
      write++;
    }
  }
  tokens_len = write;
  nr_token = tokens_len;
}

word_t expr(char *e, bool *success) {
  printf("%s\n", e);

  if (!make_token(e)) {
    *success = false;
    assert(0);
    return 0;
  }

  /* TODO: Insert codes to evaluate the expression. */
  // TODO();
  pretreatment();
  word_t tmp = eval(0, nr_token - 1);

  *success = true;
  return tmp;
}
